package memory;

import java.util.ArrayList;
import java.util.Random;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import vm.VM;
import vm.Word;
import os.*;
/**
 *
 * @author Paulius Dambrauskas
 */

public class Memory {

    public static ObservableList<Word> memory;
    public static int[] allBlocks;
    public static int blocksNumb;
    public static Boolean outOfMemory = false;
    public static int vmCount = 0;
    public Memory() {
        
        ArrayList<Word> mem = new ArrayList<>();
        memory = FXCollections.observableList(mem);
        initMemory();
        initBlocks();
    }
    private void initMemory() {
        for (int i = 0; i < VM.realMemorySize; i++){
            memory.add(new Word(i, " "));
        }
    }
    private void initBlocks() {
        blocksNumb = (VM.pageTableStart - 16*VM.stackSize) / 16;
        int start = 16*VM.stackSize; //stekas
        allBlocks = new int[blocksNumb];
        for (int i = 0; i < blocksNumb; i++) {
            allBlocks[i] = start;
            start = start + 16;
        }
    }
     /**
     * Rezervuoja atmintį stekui
     * @author Paulius Dambrauskas
     */
    private static void initStackMemory(){
         //Rezervuoja
        for (int i = 0; i < 16; i++){
            memory.get((vmCount-1)*16+i).setReservStatus(true);
            memory.get((vmCount-1)*16+i).setVirtualAddressValue(239+i);
        }
         //getSP().registerValue.set(239+""); 
    
    }
    /** 
     * @author Šarūnas Kūjalis, Paulius Dambrauskas
     * @parms programos tekstas stringe (imt iš Textareaos)
     */
    public static int loadProgram(ArrayList<ArrayList<String>> pkg){
        
        //vmCount++;   
        int returni = 0;
        for(int j = 1; j <=3; j++){
            if(memory.get((VM.pageTableStart/16+(j-1))*16).wordValue.get().equals(" ")){
                vmCount = j;
                returni = j;
                break;
            }
        }
        
        if (!isOutOfMemory()) {
            //Puslapiavimo lentele
            int[] blocks = new int[VM.numOfBlocks];
            //Programos Blokai
            blocks = genRandomBlocks();
            //Steko blokas
            blocks[15] = (vmCount-1)*16;
            initStackMemory();
            //Sugeneruoja puslapiavimo lentelę
            for (int i = 0; i < 16; i++){
                setMemory((VM.pageTableStart/16+(vmCount-1))*16+i, decToHex(blocks[i]/16)); // į lentele psl nr
            }
            
            //Užpildo steką parametrais
            int sp = VM.stackStart-1+16*(vmCount-1);
            for (int i = 0; i < pkg.get(0).size(); i++){
               sp++;
               setMemory(sp, pkg.get(0).get(i));
            }
            
            //Sukelia programos tekstą į atmintį
            for(int i = 0; i < 15; i++){
                for(int j = 0; j < 16; j++){
                    if(pkg.get(i+1).size() > j)
                        setMemory(blocks[i]+j, pkg.get(i+1).get(j));
                    /*else
                       setMemory(blocks[i]+j, " "); */
                }
            }
        }
        else {
           /* main.toolBar.setDisable(true);
            main.superPane.setVisible(true);
            main.outOfMemoryPane.setVisible(true);*/
            System.out.println("NĖRA ATMINTIES");
        }
        return returni;
    }
    /**
     * Atsitiktinai parenka blokus VM
     * @author Šarūnas Kūjalis
     * @return 
     */
    private static int[] genRandomBlocks() {
        int i = 0;
        Random randGen = new Random();
        int[] generatedBlocks = new int[VM.numOfBlocks];
        int virtualAddress = 0;
        while (i < 16) {
            int rand = randGen.nextInt(blocksNumb);
            if (!memory.get(allBlocks[rand]).getReservStatus()) {
                generatedBlocks[i] = allBlocks[rand];
                for (int j = 0; j < 16; j++) {
                    //Rezervuoja
                    memory.get(allBlocks[rand]+j).setReservStatus(true);
                    //Priskiria VA
                    memory.get(allBlocks[rand]+j).setVirtualAddressValue(virtualAddress);
                    virtualAddress++;
                }
                i++;
            }
        }
        return generatedBlocks;
    }
    /**
     * Tikrina ar yra atminties
     * @author Šarūnas Kūjalis
     * @return boolean
     */
    private static Boolean isOutOfMemory() {
        int j = 0;
        for (int i = 0; i < blocksNumb; i++) {
            if (!memory.get(allBlocks[i]).getReservStatus()) {
                j++;
            }
        }
        if (j >= VM.numOfBlocks) {
            return false;
        }
        else {
            outOfMemory = true;
            return true;
        }
    }
        /**
     * Konvertuoja hex į dec sistemą
     * @author Paulius Dambrauskas
     * @param hex
     * @return integer 
     */
    public static int hexToDec(String hex){
        return Integer.parseInt(hex, 16);
    }
    /**
     * Konvertuoja dec į hex
     * @author Paulius Dambrauskas
     * @param dec
     * @return 
     */
    public static String decToHex(int dec){
        return Integer.toHexString(dec).toUpperCase();
    }
    public static void setMemory(int address, String value){
        if (value == null) {value = "";}
        int maxLength = (value.length() < 4) ? value.length() : 4;
        value = value.substring(0, maxLength);
        memory.get(address).wordValue.set(value);
    }
    
    public static String getByAddress(int address){
        return memory.get(address).wordValue.get();
    }
    public static ObservableList<Word> getMemory() {
        return memory;
    }
    public static void cleanMem(int ptr){
        for (int j = ptr*16; j < ptr*16+16; j++) {
            int blockNr = Integer.parseInt(memory.get(j).wordValue.get(), 16);
            for(int k = blockNr*16; k < blockNr*16+16; k++){
                memory.get(k).setReservStatus(false);
                memory.get(k).wordValue.set(" ");
            }
            memory.get(j).setReservStatus(false);
            memory.get(j).wordValue.set(" ");
        }
        for(int l = ptr*16-VM.pageTableStart+VM.stackStart; l < ptr*16-VM.pageTableStart+VM.stackStart+16; l++){
            memory.get(l).setReservStatus(false);
            memory.get(l).wordValue.set(" ");  
        }
    }
}
